﻿using System;
using System.Collections.Generic;
using Shutterstock.Salesforce.Tools.SFPartner;
using System.Data;

namespace Shutterstock.Salesforce.SSISDownload
{
    public class SFFieldInfo
    {

        public fieldType Type { get; private set; }
        public int MaxLength { get; private set; }
        public int NumericScale { get; private set; }
        public int NumericPrecision { get; private set; }
        public string Name { get; private set; }

        private readonly Field m_BaseField;

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="baseField">A Salesforce Field to Base the FieldInfo on</param>
        public SFFieldInfo(Field baseField)
        {
            Type = baseField.type;
            if (baseField.byteLength > baseField.length)
            {
                MaxLength = baseField.byteLength;
            }
            else
            {
                MaxLength = baseField.length;
            }
            NumericScale = baseField.scale;
            NumericPrecision = baseField.precision;
            Name = baseField.name;
            m_BaseField = baseField;
        }

        
        /// <summary>
        /// This method returns the appriopriate line to appear in a Create Table statement... IE String might show up as varchar(max)
        /// </summary>
        /// <returns>a Create Table Fragment</returns>
        public string GetSqlServerCreateTableString()
        {
            string fieldSpecification;
            SqlDbType sqlType = SFTypeConverter.ConvertToSqlDBType(Type);
            SqlDbType finalType = sqlType;

            switch (sqlType)
            {
                //No Additions
                case SqlDbType.DateTime:
                case SqlDbType.Bit:
                case SqlDbType.Int:
                case SqlDbType.Float:
                case SqlDbType.Text:
                case SqlDbType.TinyInt:
                    fieldSpecification = "";
                    break;

                case SqlDbType.Decimal:
                    fieldSpecification = String.Format("({0},{1})", NumericPrecision, NumericScale);
                    break;
                case SqlDbType.VarBinary:
                    fieldSpecification = "(max)";
                    break;
                default:
                    if (Type == fieldType.time)
                    {
                        fieldSpecification = "(40)";
                    }
                    else
                    {
                        if (MaxLength > 512)
                        {
                            fieldSpecification = "(max)";
                        }
                        
                        else if (m_BaseField.restrictedPicklist)
                        {
                            int max = 0;
                            if (m_BaseField.picklistValues!= null && m_BaseField.picklistValues.Length > 0)
                            {
                                foreach (PicklistEntry pe in m_BaseField.picklistValues)
                                {
                                    
                                    if (pe.value.Length > max)
                                    {
                                        max = pe.value.Length;
                                    }
                                }
                                if (max > this.MaxLength)
                                {
                                    fieldSpecification = String.Format("({0})", max);
                                }
                                else
                                {
                                    fieldSpecification = String.Format("({0})", this.MaxLength);
                                }
                            }
                            else
                            {
                                fieldSpecification = "(255)";
                            }
                        }
                        else                         
                        {
                            fieldSpecification = String.Format("({0})", MaxLength);
                        }
                    }
                    break;
            }

            return String.Format("[{0}] \t{1}{2}", Name, finalType, fieldSpecification);            
        }

        /// <summary>
        /// Checks to see if an incoming set up values is the same type as the existing type
        /// </summary>
        /// <param name="type">the Name of the Type</param>
        /// <param name="maxLength"></param>
        /// <param name="numericScale"></param>
        /// <param name="numericPrecision"></param>
        /// <returns>True if the type is the same, false if its different</returns>
        public bool IsSameType(string type, int maxLength, int numericScale, int numericPrecision)
        {
            SqlDbType sqlType = SFTypeConverter.ConvertToSqlDBType(Type);
            // check type
            if (!type.Equals(sqlType.ToString(), StringComparison.OrdinalIgnoreCase))
                return false;

            switch (sqlType)
            {
                case SqlDbType.DateTime:
                case SqlDbType.Bit:
                case SqlDbType.Int:
                case SqlDbType.Float:
                case SqlDbType.Text:
                    return true;
                case SqlDbType.Decimal:
                    return (NumericPrecision == numericPrecision) && (NumericScale == numericScale);
                case SqlDbType.VarBinary:
                    return maxLength == -1;
                default:
                    if (Type == fieldType.time)
                    {
                        return maxLength == 40;
                    }
                    else
                    {
                        if (MaxLength > 512)
                        {
                            return maxLength == -1;
                        }
                        else
                        {
                            return maxLength == MaxLength;
                        }
                    }
            }
        }


        /// <summary>
        /// Checks to see if an incoming set up values is the same type as the existing type
        /// </summary>
        /// <param name="type">the Name of the Type</param>
        /// <param name="maxLength"></param>
        /// <param name="numericScale"></param>
        /// <param name="numericPrecision"></param>
        /// <returns>True if the type is the same, false if its different</returns>
        public bool IsCompatibleType(string type, int maxLength, int numericScale, int numericPrecision)
        {
            SqlDbType sqlType = SFTypeConverter.ConvertToSqlDBType(Type);
            // check type
            if (!type.Equals(sqlType.ToString(), StringComparison.OrdinalIgnoreCase))
                return false;

            switch (sqlType)
            {
                case SqlDbType.DateTime:
                case SqlDbType.Bit:
                case SqlDbType.Int:
                case SqlDbType.Float:
                case SqlDbType.Text:
                    return true;
                case SqlDbType.Decimal:
                    return (NumericPrecision == numericPrecision) && (NumericScale == numericScale);
                case SqlDbType.VarBinary:
                    return maxLength == -1;
                default:
                    if (Type == fieldType.time)
                    {
                        return maxLength == 40;
                    }
                    else
                    {
                        if (MaxLength > 512)
                        {
                            return maxLength == -1;
                        }
                        else
                        {
                            return this.MaxLength <= maxLength;
                        }
                    }
            }
        }
    }
}
